/**
 * 数字工具类
 * 提供数字处理、格式化和数学运算功能
 */
export default class NumberUtil {
  /**
   * 判断是否为整数
   * 
   * @param num 被判断的值
   * @returns 是否为整数
   */
  public static isInteger(num: any): boolean {
    return typeof num === 'number' && isFinite(num) && Math.floor(num) === num;
  }

  /**
   * 判断是否为数字
   * 
   * @param num 被判断的值
   * @returns 是否为数字
   */
  public static isNumber(num: any): boolean {
    return typeof num === 'number' && isFinite(num);
  }

  /**
   * 判断字符串是否为数字
   * 
   * @param str 字符串
   * @returns 是否为数字
   */
  public static isNumeric(str: string | null | undefined): boolean {
    if (str === null || str === undefined || str === '') {
      return false;
    }
    return !isNaN(Number(str)) && isFinite(Number(str));
  }

  /**
   * 转换为整数，空值默认为0
   * 
   * @param value 被转换的值
   * @param defaultValue 默认值
   * @returns 结果
   */
  public static toInt(value: any, defaultValue: number = 0): number {
    if (value === null || value === undefined || value === '') {
      return defaultValue;
    }
    
    const num = parseInt(String(value), 10);
    return isNaN(num) ? defaultValue : num;
  }

  /**
   * 转换为浮点数，空值默认为0
   * 
   * @param value 被转换的值
   * @param defaultValue 默认值
   * @returns 结果
   */
  public static toFloat(value: any, defaultValue: number = 0): number {
    if (value === null || value === undefined || value === '') {
      return defaultValue;
    }
    
    const num = parseFloat(String(value));
    return isNaN(num) ? defaultValue : num;
  }

  /**
   * 转换为布尔值
   * 
   * @param value 被转换的值
   * @param defaultValue 默认值
   * @returns 结果
   */
  public static toBoolean(value: any, defaultValue: boolean = false): boolean {
    if (value === null || value === undefined || value === '') {
      return defaultValue;
    }
    
    if (typeof value === 'boolean') {
      return value;
    }
    
    if (typeof value === 'string') {
      const strValue = value.toLowerCase();
      return strValue === 'true' || strValue === 'yes' || strValue === 'y' || strValue === '1';
    }
    
    if (typeof value === 'number') {
      return value === 1;
    }
    
    return defaultValue;
  }

  /**
   * 生成指定范围的随机整数
   * 
   * @param min 最小值
   * @param max 最大值
   * @returns 随机整数
   */
  public static random(min: number, max: number): number {
    return Math.floor(Math.random() * (max - min + 1) + min);
  }

  /**
   * 格式化数字，保留指定小数位
   * 
   * @param num 数字
   * @param digits 小数位数
   * @returns 格式化后的字符串
   */
  public static format(num: number, digits: number = 2): string {
    return num.toFixed(digits);
  }

  /**
   * 格式化金额，添加千位分隔符
   * 
   * @param amount 金额
   * @param digits 小数位数
   * @returns 格式化后的字符串
   */
  public static formatMoney(amount: number, digits: number = 2): string {
    return amount.toLocaleString('zh-CN', {
      minimumFractionDigits: digits,
      maximumFractionDigits: digits
    });
  }

  /**
   * 格式化文件大小
   * 
   * @param size 文件大小(字节)
   * @param digits 小数位数
   * @returns 格式化后的字符串
   */
  public static formatFileSize(size: number, digits: number = 2): string {
    const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
    let i = 0;
    while (size >= 1024 && i < units.length - 1) {
      size /= 1024;
      i++;
    }
    return size.toFixed(digits) + ' ' + units[i];
  }

  /**
   * 格式化百分比
   * 
   * @param value 值（0-1之间）
   * @param digits 小数位数
   * @returns 格式化后的字符串
   */
  public static formatPercent(value: number, digits: number = 2): string {
    return (value * 100).toFixed(digits) + '%';
  }

  /**
   * 限制数字在指定范围内
   * 
   * @param num 数字
   * @param min 最小值
   * @param max 最大值
   * @returns 限制后的数字
   */
  public static clamp(num: number, min: number, max: number): number {
    return Math.min(Math.max(num, min), max);
  }

  /**
   * 四舍五入到指定小数位
   * 
   * @param num 数字
   * @param digits 小数位数
   * @returns 四舍五入后的数字
   */
  public static round(num: number, digits: number = 0): number {
    const multiplier = Math.pow(10, digits);
    return Math.round(num * multiplier) / multiplier;
  }

  /**
   * 向上取整到指定小数位
   * 
   * @param num 数字
   * @param digits 小数位数
   * @returns 向上取整后的数字
   */
  public static ceil(num: number, digits: number = 0): number {
    const multiplier = Math.pow(10, digits);
    return Math.ceil(num * multiplier) / multiplier;
  }

  /**
   * 向下取整到指定小数位
   * 
   * @param num 数字
   * @param digits 小数位数
   * @returns 向下取整后的数字
   */
  public static floor(num: number, digits: number = 0): number {
    const multiplier = Math.pow(10, digits);
    return Math.floor(num * multiplier) / multiplier;
  }

  /**
   * 判断数字是否为奇数
   * 
   * @param num 数字
   * @returns 是否为奇数
   */
  public static isOdd(num: number): boolean {
    return Math.abs(num % 2) === 1;
  }

  /**
   * 判断数字是否为偶数
   * 
   * @param num 数字
   * @returns 是否为偶数
   */
  public static isEven(num: number): boolean {
    return num % 2 === 0;
  }

  /**
   * 计算两个数的最大公约数
   * 
   * @param a 第一个数
   * @param b 第二个数
   * @returns 最大公约数
   */
  public static gcd(a: number, b: number): number {
    a = Math.abs(a);
    b = Math.abs(b);
    
    // 使用欧几里得算法
    while (b !== 0) {
      const temp = b;
      b = a % b;
      a = temp;
    }
    
    return a;
  }

  /**
   * 计算两个数的最小公倍数
   * 
   * @param a 第一个数
   * @param b 第二个数
   * @returns 最小公倍数
   */
  public static lcm(a: number, b: number): number {
    return Math.abs(a * b) / this.gcd(a, b);
  }

  /**
   * 将数字填充到指定长度
   * 
   * @param num 数字
   * @param size 目标长度
   * @returns 填充后的字符串
   */
  public static padLeft(num: number, size: number): string {
    return num.toString().padStart(size, '0');
  }

  /**
   * 计算阶乘
   * 
   * @param n 非负整数
   * @returns 阶乘结果
   */
  public static factorial(n: number): number {
    if (!Number.isInteger(n) || n < 0) {
      throw new Error('阶乘只适用于非负整数');
    }
    
    if (n <= 1) {
      return 1;
    }
    
    let result = 1;
    for (let i = 2; i <= n; i++) {
      result *= i;
    }
    
    return result;
  }

  /**
   * 判断是否为质数
   * 
   * @param n 数字
   * @returns 是否为质数
   */
  public static isPrime(n: number): boolean {
    if (!Number.isInteger(n) || n <= 1) {
      return false;
    }
    
    if (n <= 3) {
      return true;
    }
    
    if (n % 2 === 0 || n % 3 === 0) {
      return false;
    }
    
    const sqrtN = Math.sqrt(n);
    for (let i = 5; i <= sqrtN; i += 6) {
      if (n % i === 0 || n % (i + 2) === 0) {
        return false;
      }
    }
    
    return true;
  }

  /**
   * 生成UUID
   * 
   * @returns UUID字符串
   */
  public static uuid(): string {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      const r = Math.random() * 16 | 0;
      const v = c === 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  }
} 